/**
 * Created by 鄢鹏权 on 2017/04/09.
 */
///<reference path="../../DefinitelyTyped/jquery/jquery.d.ts"/>
    declare let mui:any;
namespace Castle {
    export class Request {
        static request = {};
        static link = {};
        static push = {};
        /**
         * 发送post请求
         * @param url 请求地址
         * @param data 请求数据
         * @param success 成功回调
         * @param error 失败回调
         */
        static post(url: string, data, success, error?: Function) {
            Request.ajax.apply(this, [url, '', data, success, error])
        }

        static get(url, success, error?: Function) {
            Request.ajax.apply(this, [url, '', '', success, error])
        }

        static getHtml(url, success?, error?) {
            // if(url.substr(0,4)=='file'){
                let p = /([A-Za-z]{1,})\/([A-Za-z]{1,})_([A-Za-z]{1,})\.html/.exec(url);
                if(p&&p.length==4){
                    let html = Config.getHTML(p[2],p[3],p[1]);
                    if(html.length>0||window.location.protocol=='file:'){
                        if(success instanceof Function)
                            success.apply(this,[html]);
                        return ;
                    }
                }
            // }
            let config:any = {
                method: "GET",
                mode: "cors",
                credentials: "include",
                cache:'reload'
            };
            let that = this;
            Config.requestStart();
            // Castle.Request.ajax(url,'','',success,error);
            fetch(url, config).then(function (response) {
                Config.requestEnd();
                return response.text();
            }).then(function (d) {
                if ('function' === typeof success)
                    success.apply(that, [d])
            }).catch(function (err) {
                if ('function' === typeof error)
                    error.apply(that, [err])
            })
        }

        static getJs(url, success, error) {
            let config:any = {
                method: "GET",
                mode: "cors",
                credentials: "include"
            };
            let that = this;
            Config.requestStart();
            fetch(url, config).then(function (response) {
                Config.requestEnd();
                return response.text();
            }).then(function (d) {
                success.apply(that, [d])
            })
        }

        static getCss(url) {
            let link = document.createElement("link");
            link.type = "text/css";
            link.rel = "stylesheet";
            link.href = url;
            document.getElementsByTagName("head")[0].appendChild(link);
        }

        static getStyle(cssText: string) {
            let style = document.createElement("style");
            style.type = "text/css";
            try {
                // firefox、safari、chrome和Opera
                style.appendChild(document.createTextNode(cssText));
            } catch (ex) {
            }
            document.getElementsByTagName("head")[0].appendChild(style);
        }

        static success = function (d, xhr, success, error,host) {
            if (d instanceof Object) {
                if(host==Config.Host){
                    let UID = 0;
                    let UN = '';
                    let Groups: any = [0];
                    if (d.UID instanceof String || d.UID instanceof Number || typeof d.UID == 'string' || typeof d.UID == 'number') {
                        UID = Number(d.UID)
                    }
                    if (d.UN instanceof String || typeof d.UN == 'string') {
                        UN = d.UN
                    }
                    if (d.G instanceof Array || d.G instanceof String || typeof d.G == 'string') {
                        if (d.G instanceof String || typeof d.G == 'string') {
                            d.G = d.G.split(',')
                        }
                        for (let x in d.G) {
                            if (d.G[x] && Number(d.G[x])) {
                                Groups.push(Number(d.G[x]))
                            }
                        }
                        if (!Groups.contains(0))
                            Groups.push(0)
                        Groups.uniquelize()
                    }
                    let p = false;
                    for (let i = 0; i < Groups.length; i++) {
                        if (index.user.Groups.indexOf(Groups[i]) < 0) {
                            p = true;
                            break;
                        }
                    }
                    if (UID != index.user.UID) {
                        index.user.UID = UID
                    }
                    if (UN != index.user.UN) {
                        index.user.UN = UN
                    }
                    if (p) {
                        index.user.Groups = Groups
                    }
                }
                if ((typeof d.err == "string" && d.err.length > 0 )) {
                    // 错误
                    if (typeof error == "function")
                        error.apply(this, [d.err, d.c])
                    else {
                        console.log(d)
                    }
                } else {
                    if (typeof success == "function")
                        success.apply(this, [d.d, d])
                }
            } else if (typeof d == 'string') {
                if(xhr){
                    if(xhr.responseURL.lastIndexOf('html')>-1){
                        // html模式
                        success.apply(this,[d])
                    }else if(xhr.responseURL.lastIndexOf('js')>-1){

                    }
                }
            } else {

            }
        };

        /**
         *
         * @param url
         * @param selector
         * @param data
         * @param success
         * @param error
         * @example
         * Castle.Request.upload(Config.getRequestUrl('Drug','upload'),'#drug-file',{
                IsPass:true,
            },function (data) {

            },function(){

            })
         */
        static upload(url, selector, data, success, error) {
            // let input: any = document.querySelectorAll(selector);
            let formData = new FormData();
            if($(selector).val()) {
                $.each($(selector),function (i,v) {
                    let fileList = $(v).get(0).files;
                    for(let x=0;x<fileList.length;x++) {
                        formData.append('file'+x, fileList.item(x));
                    }
                })
            }
            let host='';
            fetch(url, {
                method: 'POST',
                mode: "cors",
                credentials: "include",
                // headers:{
                //     'Content-Type':'multipart/form-data;charset=utf-8'
                // },
                body: formData
            }).then(function (response) {
                host=response.url.split('/')[2];
                return response.json();
            }).then(function (d:any) {
                if (d instanceof Object) {
                    if (typeof d.err == "string" && d.err.length > 0) {
                        // 错误
                        if (typeof error == "function")
                            error.apply(this, [d.err, d.c])
                        else {

                        }
                    } else {
                        if (typeof success == "function")
                            success.apply(this, [d.d])
                    }
                } else if (d instanceof String) {

                } else {

                }
            })
        }

        static ajax(url: string, get?: any, post?: any, success?: Function, error?: Function) {
            let that = this;
            let g = {};
            if (get) {
                avalonData.apply(g, [get]);
            }
            let p = {};
            if (post) {
                avalonData.apply(p, [post]);
            }
            let path = Crypt.hex_md5(url + JSON.stringify(g) + JSON.stringify(p));
            if (Castle.Request.request[path]) {
                return;
            } else {
                Castle.Request.request[path] = setTimeout(function () {
                    clearTimeout(Castle.Request.request[path]);
                    delete Castle.Request.request[path];
                }, 500)
            }

            let config:any = {
                url: url,
                type: post ? 'POST' : 'GET',
                data: {}

                , success: function (d, status,xhr) {
                    Castle.Request.success.apply(that, [d, xhr, success, error]);
                }, error: function (err) {

                }
            };
            if (post) {
                config.data = {};
                avalonData.apply(config.data, [post]);
            }
            switch (Config.RequestMethod){
                case 'fetch':
                    config = {
                        mode: "cors",
                        credentials: "include"
                        , body: '',
                        method: (post ? "POST" : "GET"),
                        // headers:{
                        //     'Content-Type':'application/json'
                        // }
                    };
                    if (post) {
                        let d = {}
                        avalonData.apply(d, [post])
                        config.body = JSON.stringify(d)
                    } else {
                        delete config.body;
                    }
                    Config.requestStart();
                    let host='';
                    fetch(url, config).then(function (response) {
                        Config.requestEnd();
                        host=response.url.split('/')[2];
                        return response.json();
                    }).then(function (d) {
                        Castle.Request.success.apply(that, [d, {}, success, error,host]);
                    })
                    break;
                case 'jquery':
                    if ($) {

                    } else {
                        loadJs('http://cdn.bootcss.com/jquery/3.2.1/jquery.min.js');
                    }
                    $.ajax(config);
                    break;
                case 'mui':
                    mui.ajax(config);
                    break;
            }
        }

        static down(options) {
            if (window['jQuery']) {
                let config = $.extend(true, {method: 'post'}, options);
                let $iframe = $('<iframe id="down-file-iframe" />');
                let $form: any = $('<form target="down-file-iframe" method="' + config.method + '" />');
                $form.attr('action', config.url);
                let Data = {}, d: string;
                avalonData.apply(Data, [config.data]);
                for (let key in Data) {
                    if (typeof Data[key] == 'object')
                        Object.keys(Data[key]).forEach(function (k) {
                            $form.append('<input type="hidden" name="' + key +'['+k+']'+ '" value="' + Data[key][k] + '" />');
                        })
                    else {
                        d = Data[key]
                        $form.append('<input type="hidden" name="' + key + '" value="' + d + '" />');
                    }
                }
                $iframe.append($form);
                $(document.body).append($iframe);
                $form[0].submit();
                $iframe.remove();
            } else {
                let rurl = options.url;
                let filename = options.filename;
                delete options.url;
                delete options.filename;
                options = avalon.mix({
                    method: "post",
                    mode: "cors",
                    credentials: "include",
                    data: ''
                }, options)
                if (typeof options.data != 'string') {
                    let d = {};
                    avalonData.apply(d, [options.data]);
                    options.body = JSON.stringify(d);
                    delete options.data;
                }
                // TODO 下载不支持多次下载
                fetch(rurl, options).then(res => res.blob().then(blob => {
                    let a: any = document.createElement('a');
                    a.href = window.URL.createObjectURL(blob);
                    a.download = filename;
                    a.click();
                    window.URL.revokeObjectURL(a.href);
                    a.remove();
                }));
            }
        }

        static ws(url: string) {
            Castle.Request.link[url] = {
                ws: new WebSocketClient(url),
                msg: {},
                url:url
            };
            return Castle.Request.link[url];
        }
        static pushConfig(url,func){
            Castle.Request.push[url]={
                o:this,
                f:func
            }
        }

        /**
         * 发起Websocket请求
         * @param i 请求接口
         * @param d 请求参数
         * @param success 成功回调
         * @param error 错误回调
         * @param t 指定消息编号
         * @param url 要发送的服务器地址，默认为已建立连接的第一个
         * @returns {boolean}
         */
        static cmd(i, d, success:Function=null, error:Function=null, t = '', url = '') {
            let wsc:any = false;
            if (url.length > 5) {
                if (url.substr(-1) != '/') url += '/';
                if (Castle.Request.link[url] == undefined) {
                    wsc = Castle.Request.ws(url);
                } else {
                    wsc = Castle.Request.link[url];
                }
            } else {
                //取第一个
                if (Object.keys(Castle.Request.link).length>0) {
                    wsc=Castle.Request.link[Object.keys(Castle.Request.link)[0]]
                } else {
                    //TODO 调用系统错误
                    return false;
                }
            }
            if (wsc) {
                let ps = {};
                avalonData.apply(ps,[d]);
                let data = {
                    i: i,
                    d: ps,
                    t: t.length>0?t:(new Date()).valueOf(),
                    m:''
                };
                if(wsc.msg[data.i+data.t]){
                    //已存在该消息指令，忽略
                }else{
                    //发送指令
                    wsc.ws.send.apply(wsc.ws,[data,wsc.url])
                    wsc.msg[data.i+data.t]={
                        success:success,
                        error:error,
                        d:d,
                        o:this
                    }
                }
            }else{

            }
        }
    }
    export class WebSocketClient {
        public ws: WebSocket;
        public url;

        constructor(url: string) {
            this.create(url);
        }

        public create(url) {
            try {
                this.url = url;
                this.ws = new WebSocket(url);
                this.ws.onclose = function (event) {
                    Castle.Request.link[url].ws.close.apply(Castle.Request.link[url].ws, [event, url])
                };
                this.ws.onmessage = function (event) {
                    Castle.Request.link[url].ws.receive.apply(Castle.Request.link[url].ws, [event, url])
                };
                this.ws.onopen = function (event) {
                    Castle.Request.link[url].ws.connect.apply(Castle.Request.link[url].ws, [event, url])
                };
                this.ws.onerror = function (event) {
                    Castle.Request.link[url].ws.error.apply(Castle.Request.link[url].ws, [event, url])
                };
            } catch (e) {

            }
        }

        public error(event, url) {
            console.log(event)
        }

        public connect(event, url) {
            console.log(event)
        }

        public close(event, url) {
            console.log(event)
            let that = this;
            setTimeout(function () {
                that.create(that.url)
            },3000);

        }

        public receive(event, url) {
            this.dispatch(this.decode(event.data, url), url)
        }

        public send(data, url) {
            if(this.ws.readyState==this.ws.OPEN)
                this.ws.send(this.encode(data, url)+"\r\n\r\n");
            else
            {
                let that = this;
                setTimeout(function () {
                    that.send(data,url)
                },100)
            }
        }

        public dispatch(data, url) {
            let msg = Castle.Request.link[this.url].msg[data.i+data.t];
            if(msg){
                Castle.Request.success.apply(msg.o,[data,null,msg.success,msg.error]);
                delete Castle.Request.link[this.url].msg[data.i+data.t];
            }else{
                this.push(data,url);
            }
        }
        public push(data,url){
            let config=Castle.Request.push[url];
            if(config&&typeof config.f == 'function'){
                config.f.apply(config.o,[data])
            }
        }
        public encode(data, url) {
            return JSON.stringify(data);
        }

        public decode(data, url) {
            return JSON.parse(data)
        }
    }
}